package com.shelpe.services.sinbad.controller.sinbad;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.shelpe.services.sinbad.controller.dto.ProductDto;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.AutoProductQueue;
import com.shelpe.services.sinbad.entity.jpa.Campaign;
import com.shelpe.services.sinbad.entity.jpa.DriveType;
import com.shelpe.services.sinbad.entity.jpa.Product;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.AutoProductQueueRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping(value = "/sinbadservice/v2")
@Api("v2产品信息相关的API")
@Slf4j
public class ProductController {
	public final static Predicate[] TEMPLATE = new Predicate[0];
	@Autowired
	private EntityManager em;
	@Autowired
	private CampaignRepository campaignRepository;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private AutoProductQueueRepository autoProductQueueRepository;

	@ApiOperation(value = "产品列表的获取")
	@RequestMapping(method = RequestMethod.GET, path = "/users/{user_id}/products")
	public Page<ProductDto> findProducts(@PathVariable("user_id") final long userID,
			@RequestParam(name = "campaign_id", defaultValue = "0", required = false) final long campaignID,
			@RequestParam(name = "page_num", defaultValue = "0") int page,
			@RequestParam(name = "page_size", defaultValue = "15") int size,
			@RequestParam(name = "search_title", required = false) final String searchTitle,
			@RequestParam(name = "sort", defaultValue = "sales_count") String sort,
			@RequestParam(name = "direct", defaultValue = "desc") String direct,
			@RequestParam(name = "is_filter", defaultValue = "true", required = false) final boolean filter) {
		List<Long> productIDs = null;
		if (campaignID > 0) {
			productIDs = this.getCampaignDownProductID(campaignID);
		}
		List<ProductDto> dtos = new ArrayList<ProductDto>();

		// CriteriaBuilder,用来构建CritiaQuery的构建器对象
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		// CriteriaQuery,它包含着查询语句的条件各个部分，比如：select 、from、where、group by、orderby等
		CriteriaQuery<Product> criteriaQuery = criteriaBuilder.createQuery(Product.class);
		// 查询根，用于获取查询实例的属性，通过CriteriaQuery的from方法获取
		Root<Product> rootFrom = criteriaQuery.from(Product.class);
		// 查询条件
		List<Predicate> predicates = new ArrayList<Predicate>();
		predicates.add(criteriaBuilder.equal(rootFrom.get("userID"), userID));
		if (campaignID > 0) {
			if (filter) {
				if (productIDs != null && productIDs.size() > 0) {
					predicates.add(rootFrom.<Long>get("productID").in(productIDs).not());// 有值，过滤，没值，跳过此条件
				}
			} else if (!filter) {
				if (productIDs != null && productIDs.size() > 0) {
					predicates.add(rootFrom.<Long>get("productID").in(productIDs));// 集合有值，查询。没值直接返回空
				} else {
					return new PageImpl<ProductDto>(dtos, new PageRequest(page, size), 0);
				}
			}
		}
		if (StringUtils.isNotBlank(searchTitle)) {
			predicates.add(criteriaBuilder.like(rootFrom.get("productName"), "%" + searchTitle + "%"));
		}
		// 格式化参数
		criteriaQuery.where(criteriaBuilder.and(predicates.toArray(TEMPLATE)));
		// 默认按照id排序（从小到大）
		List<Order> orders = new ArrayList<Order>();
		if ("publish_time".equals(sort)) {
			sort = "publishTime";
		} else if ("sales_count".equals(sort)) {
			sort = "sales";
		}
		if ("asc".equals(direct)) {
			orders.add(criteriaBuilder.asc(rootFrom.get(sort)));
		} else {
			orders.add(criteriaBuilder.desc(rootFrom.get(sort)));
		}
		criteriaQuery.orderBy(orders);
		// SQL查询对象
		TypedQuery<Product> createQuery = em.createQuery(criteriaQuery);
		// 分页参数
		Integer pageSize = size;
		Integer pageNo = page;
		// 计数查询结果条数
		TypedQuery<Product> createCountQuery = em.createQuery(criteriaQuery);
		// 实际查询返回分页对象
		createQuery.setFirstResult(pageNo * pageSize);
		createQuery.setMaxResults(pageSize);

		List<Adgroup> adgroups = null;
		if (productIDs != null && productIDs.size() > 0) {
			adgroups = this.adgroupRepository.findByCampaignIDAndProductIDIn(campaignID, productIDs);
		}
		Map<Long, Adgroup> map = new HashMap<Long, Adgroup>();
		if (adgroups != null && adgroups.size() > 0) {
			for (Adgroup adgroup : adgroups) {
				map.put(adgroup.getProductID(), adgroup);
			}
		}

		if (createQuery.getResultList() != null && createQuery.getResultList().size() > 0) {
			for (Product po : createQuery.getResultList()) {
				Adgroup adgroup = map.get(po.getProductID());
				ProductDto dto = new ProductDto();
				dto.setAdgroup(new ProductDto.AdgroupDto());
				if (adgroup != null) {
					dto.getAdgroup().from(adgroup);
				}
				dto.from(po);
				dtos.add(dto);
			}
		}
		return new PageImpl<ProductDto>(dtos, new PageRequest(page, size), createCountQuery.getResultList().size());
	}

	/******* 业务相关的方法 *****注:如果是低价模式，则是过滤用户级别 ***/
	private List<Long> getCampaignDownProductID(long campaignID) {
		List<Long> existProductIDs = new ArrayList<Long>();
		Campaign campaign = this.campaignRepository.findOne(campaignID);
		if (campaign != null) {
			if (DriveType.auto == campaign.getAutoType()) {
				List<Long> needCampaignIDs = new ArrayList<Long>();
				needCampaignIDs.add(campaign.getAutoID());
				List<Long> productIDs = null;
				productIDs = this.adgroupRepository.findProductIDsByCampaignIDs(needCampaignIDs);
				List<Long> queueAddProductIDs = null;
				long start1 = System.currentTimeMillis();
				queueAddProductIDs = this.autoProductQueueRepository.findProductIDsByCampaignID(campaignID, AutoProductQueue.Status.added);// 待填充的推广组
				log.info("select autoQueue added cost {} ms", System.currentTimeMillis() - start1);
				List<Long> queueSuccessProductIDs = null;
				long start2 = System.currentTimeMillis();
				queueSuccessProductIDs = this.autoProductQueueRepository.findProductIDsByCampaignID(campaignID, AutoProductQueue.Status.success);// 已完成的推广组
				log.info("select autoQueue success cost {} ms", System.currentTimeMillis() - start2);
				if (queueSuccessProductIDs != null && queueSuccessProductIDs.size() > 0) {
					List<Long> deleteProductIDs = new ArrayList<Long>();
					if(productIDs != null && productIDs.size() > 0 ){
						for(long productID : productIDs){
							if(!queueSuccessProductIDs.contains(productID)){
								deleteProductIDs.add(productID);
							}
						}
					} else {
						deleteProductIDs.addAll(queueSuccessProductIDs);
					}
					if (deleteProductIDs != null && deleteProductIDs.size() > 0) {
						long start3 = System.currentTimeMillis();
						this.autoProductQueueRepository.deleteByProductIDIn(deleteProductIDs);
						log.info("select autoQueue delete cost {} ms", System.currentTimeMillis() - start3);
					}
				}
				if (queueAddProductIDs != null && queueAddProductIDs.size() > 0) {
					for (long queueID : queueAddProductIDs) {
						if (existProductIDs.indexOf(queueID) == -1) {
							existProductIDs.add(queueID);
						}
					}
				}
				if (productIDs != null && productIDs.size() > 0) {
					for (long productID : productIDs) {
						if (existProductIDs.indexOf(productID) == -1) {
							existProductIDs.add(productID);
						}
					}
				}
			} else {
				List<Long> productIDs = this.adgroupRepository.findProductIDsByCampaignID(campaignID);
				if (productIDs != null && productIDs.size() > 0) {
					existProductIDs.addAll(productIDs);
				}
			}
		}
		return existProductIDs;
	}
}
